/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.tukano.swingdeco.input;

import it.tukano.collections.ArrayListExt;
import it.tukano.collections.ListExt;
import it.tukano.fun.Function0;
import it.tukano.fun.Function1;
import it.tukano.fun.VFunction1;
import it.tukano.fun.VFunction2;
import it.tukano.swingdeco.JLabelExt;
import it.tukano.swingdeco.containers.JFrameExt;
import it.tukano.swingdeco.containers.JPanelExt;
import it.tukano.swingdeco.controls.JButtonExt;
import it.tukano.swingdeco.controls.JComboBoxExt;
import it.tukano.swingdeco.event.InputAdapter;
import it.tukano.swingdeco.event.MouseEventExt;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.GridLayout;
import java.util.Calendar;
import java.util.Locale;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

/**
 *
 * @author utente4
 */
public class CalendarChooser extends JPanel {
    
    //Default serial version code
    private static final long serialVersionUID = 0;
    
    private final JComboBoxExt monthBox = new JComboBoxExt();
    private final JComboBoxExt yearBox = new JComboBoxExt();
    private final InputAdapter clickHandler = new InputAdapter() {

        @Override
        protected void onLeftMouseClicked(MouseEventExt e) {
            JLabelExt label = (JLabelExt) e.getComponent();
            CalendarChooser.this.notifyListeners(label);
        }
    };
    private final ListExt<JLabelExt> dayLabels = new ArrayListExt<JLabelExt>().addAll(new Function0<JLabelExt>() {
        int count = 42;
        int i = 0;
        Dimension size = new Dimension(30,30);

        public JLabelExt apply() {
            if(i == count) return null;
            i++;
            JLabelExt box = new JLabelExt(i);
            box.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            box.addMouseListener(clickHandler);
            box.setPreferredSize(size);
            box.setHorizontalAlignment(JLabel.CENTER);
            box.setBackground(Color.WHITE);
            box.setForeground(Color.BLACK);
            box.setOpaque(true);
            box.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            return box;
        }
    });
    private Function1<Calendar, ?> listener = null;
    
    public CalendarChooser() {
        super(new BorderLayout());
    }
    
    public void setCalendar(Calendar c) {
        initializeUi(c);
    }

    private void initializeUi(final Calendar time) {
        final JPanelExt boxContainer = new JPanelExt(new GridLayout(6, 7, 4, 4));
        for (JLabelExt jLabelExt : dayLabels) {
            boxContainer.add(jLabelExt);
        }
        int minDay = time.getMinimum(Calendar.DAY_OF_WEEK);
        int maxDay = time.getMaximum(Calendar.DAY_OF_WEEK);
        ListExt<String> dayNames = new ArrayListExt<String>(maxDay - minDay);
        {
            Calendar temp = (Calendar) time.clone();
            for(int i = minDay; i <= maxDay; i++) {
                temp.set(Calendar.DAY_OF_WEEK, i);
                String name = temp.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault());
                dayNames.add(name);
            }
        }
                
        int minMonth = time.getMinimum(Calendar.MONTH);
        int maxMonth = time.getMaximum(Calendar.MONTH);
        
        for(int i = minMonth; i <= maxMonth; i++) {
            monthBox.append(i);
        }
        
        for(int i = 1900; i < 2200; i++) {
            yearBox.append(i);
        }
        monthBox.onSelectionChange(new Runnable() {

            public void run() {
                time.set(Calendar.MONTH, (Integer) monthBox.getSelectedItem());
                setStateToMatchTime(time);
            }
        });
        yearBox.onSelectionChange(new Runnable() {

            public void run() {
                time.set(Calendar.YEAR, (Integer) yearBox.getSelectedItem());
                setStateToMatchTime(time);
            }
        });
        monthBox.withSimpleRenderer(new VFunction2<Object, JLabel>() {
            Calendar temp = (Calendar) time.clone();

            @Override
            public void doApply(Object a, JLabel b) {
                Integer i = (Integer) a;
                temp.set(Calendar.MONTH, i);
                String s = temp.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
                b.setText(s);
            }
        });
        JPanelExt dayHeaders = new JPanelExt(new GridLayout(1, dayNames.size()));
        for (String string : dayNames) {
            string = string.substring(0, 1).toUpperCase() + string.substring(1);
            JLabelExt label = new JLabelExt(string);
            label.alignCenter();
            label.scaleFont(0.75f);
            dayHeaders.add(label);
        }
        JPanelExt northBar = new JPanelExt(new BorderLayout(10, 10))
                .append(monthBox, BorderLayout.CENTER)
                .append(yearBox, BorderLayout.EAST)
                .append(dayHeaders, BorderLayout.SOUTH);
        setLayout(new BorderLayout(10, 10));
        add(boxContainer, BorderLayout.CENTER);
        add(northBar, BorderLayout.NORTH);
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setStateToMatchTime(time);
    }
    
    public Calendar getCalendar() {
        return Calendar.getInstance();
    }
    
    public static void showPopup(Component parent, Calendar value, final Function1<Calendar, ?> onAccept) {
        final JPopupMenu popup = new JPopupMenu();
        final CalendarChooser cc = new CalendarChooser();
        popup.add(cc);
        cc.initializeUi(value == null ? Calendar.getInstance() : value);
        cc.listener = new VFunction1<Calendar>() {

            @Override
            protected void doApply(Calendar p) {
                popup.setVisible(false);
                if(onAccept != null) onAccept.apply(p);
            }
        };
        popup.show(parent, 0, parent.getHeight());
    }
    
    public static void showDialog(Component parent, Calendar value, boolean modal, final Function1<Calendar, ?> onAccept) {
        final Frame parentFrame = JOptionPane.getFrameForComponent(parent);
        final JDialog dialog = new JDialog(parentFrame, modal);
        final CalendarChooser ch = new CalendarChooser();
        ch.initializeUi(value);
        ch.listener = new VFunction1<Calendar>() {

            @Override
            protected void doApply(Calendar p) {
                dialog.dispose();
                if(onAccept != null) onAccept.apply(p);
            }
        };
        JPanelExt container = new JPanelExt(new BorderLayout())
                .append(ch, BorderLayout.CENTER);
        dialog.setContentPane(container);
        dialog.pack();
        dialog.setLocationRelativeTo(parent);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
    }
    
    private void setStateToMatchTime(Calendar time) {
        Calendar now = Calendar.getInstance();
        boolean paintToday = 
                (now.get(Calendar.YEAR) == time.get(Calendar.YEAR)) 
                && 
                (now.get(Calendar.MONTH) == time.get(Calendar.MONTH));
        int today = -1;
        if(paintToday) {
            today = time.get(Calendar.DAY_OF_MONTH) + 1;
        }
        yearBox.setSelectedItem(time.get(Calendar.YEAR));
        monthBox.setSelectedItem(time.get(Calendar.MONTH));
        Calendar temp = (Calendar) time.clone();
        temp.set(Calendar.DAY_OF_MONTH, time.getActualMinimum(Calendar.DAY_OF_MONTH));
        int dayOfWeek = temp.get(Calendar.DAY_OF_WEEK);
        int shift = dayOfWeek - 1;
        int max = time.getActualMaximum(Calendar.DAY_OF_MONTH);
        int day = 1;
        for(int i = 0; i < dayLabels.size(); i++) {
            JLabelExt label = dayLabels.get(i);
            if(i < shift || day > max) {
                label.setVisible(false);
            } else {
                label.setText(String.valueOf(day));
                label.setVisible(true);
                day++;
            }
            if(day == today) {
                label.setBackground(Color.GREEN);
            } else {
                label.setBackground(Color.WHITE);
            }
        }
    }
    
    private void notifyListeners(JLabelExt label) {
        Integer day = new Integer(label.getText());
        Calendar c = Calendar.getInstance();
        c.set((Integer) yearBox.getSelectedItem(), (Integer) monthBox.getSelectedItem(), day);
        if(listener != null) {
            listener.apply(c);
        }
    }
    
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                final JButtonExt button = new JButtonExt("Popup");
                button.onAction(new Runnable() {

                    public void run() {
                        CalendarChooser.showPopup(button, null, new VFunction1<Calendar>() {

                            @Override
                            protected void doApply(Calendar p) {
                                System.out.println(p.getTime());
                            }
                        });
                    }
                });
                new JFrameExt("test")
                        .defaultDispose()
                        .append(button, BorderLayout.CENTER)
                        .packAndShow();
            }
        });
    }
}
